package com.carefree.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.SecretKey;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * @ClassName:JwtUtils
 * @Description: 生成JSON Web令牌的工具类
 * @Author Tengbin tengbin234@163.com
 */
public class JwtUtils {

    /**
     * 过期时间 24小时
     */
    public static final long TOKEN_EXPIRATION = 24 * 60 * 60 * 1000;

    /**
     * 加密密钥
     */
    private static final String SIGNKEY = "B:1$mDIMef40A@(49vP;kE6BG}79>[B:1$mDIMef40A@(49vP;kE6BG}79>";

    /**
     * 生成 token
     *
     * @param userId   用户id
     * @param username 用户名
     * @return
     */
    public static String createToken(Long userId, String username) {
        return Jwts.builder()
                //  主题
                .setSubject("AUTH-USER")
                // 过期时间: 当前系统时间后的TOKEN_EXPIRATION的时间
                .setExpiration(new Date(System.currentTimeMillis() + TOKEN_EXPIRATION))
                // 有效载荷
                .claim("userId", userId).claim("username", username)
                // 编码加密
                .signWith(generateHmacShaKey())
                // 使用gzip压缩
                .compressWith(CompressionCodecs.GZIP).compact();
    }

    public static String createToken(Map<String, Object> claims) {
        return Jwts.builder()
                //  主题
                .setSubject("AUTH-USER")
                // 过期时间: 当前系统时间后的TOKEN_EXPIRATION的时间
                .setExpiration(new Date(System.currentTimeMillis() + TOKEN_EXPIRATION))
                // 有效载荷
                .setClaims(claims)
                // 编码加密
                .signWith(generateHmacShaKey())
                // 使用gzip压缩
                .compressWith(CompressionCodecs.GZIP).compact();
    }


    /**
     * 生成加密密钥
     *
     * @param singnKey
     * @return
     */
    private static SecretKey generateHmacShaKey() {
        byte[] encode = Base64.getMimeEncoder().encode(SIGNKEY.getBytes());
        return Keys.hmacShaKeyFor(encode);
    }

    /**
     * 根据token获取其中的有效载荷userId
     *
     * @param token
     * @return
     */
    public static Long parseTokenGetUserId(String token) {
        try {
            if (StringUtils.isEmpty(token)) return null;
            Integer userId = (Integer) getClaimsFromToken(token).get("userId");
            return userId.longValue();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据token获取其中的有效载荷userName
     *
     * @param token
     * @return
     */
    public static String parseTokenGetUsername(String token) {
        try {
            if (StringUtils.isEmpty(token)) return "";
            return (String) getClaimsFromToken(token).get("username");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取token中的有效载荷
     *
     * @param token
     * @return
     */
    private static Claims getClaimsFromToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(generateHmacShaKey()).parseClaimsJws(token);
        return claimsJws.getBody();
    }

    /**
     * 判断token是否已经失效
     *
     * @param token
     * @return
     */
    public static boolean isTokenExpired(String token) {
        Date expireDate = getExpiredDateFromToken(token);
        return expireDate.before(new Date());
    }

    /**
     * 获取token中过期时间
     *
     * @param token
     * @return
     */
    private static Date getExpiredDateFromToken(String token) {
        return getClaimsFromToken(token).getExpiration();
    }

    /**
     * 判断当前token是否可以刷新(续期)
     *
     * @param token
     * @return
     */
    public boolean canRefresh(String token) {
        return ! isTokenExpired(token);
    }

    /**
     * 刷新(续期) token
     *
     * @param token
     * @return
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return createToken(claims);
    }


}
